#ifndef REALCPU_CU
#define REALCPU_CU

#include "realCPU.cuh"
#include "../fitness/fitnessReal.cu"

/******************* Implementacion de Funciones del  *****************/


 void inicializarPoblacionRealCPU(float* poblacion, float* fitnessActual, MersenneTwister *mt, int cantCromosomasPoblacion, float* fitnessOrdenadoHostCPU){
	//Obtengo posicion a escribir.
	int posicionCromosoma = 0;
	int posicionFitness = 0;
	for(int i = 0; i < cantGenesEnCromosoma * cantidadPoblacionesCPU * cantCromosomasPoblacion; i++){
		//Genero valor aleatorio.
		float r = (obtenerNumeroEnRangoRealCPU(mt->genrand_real1()));
		//float r = (mt->genrand_real1())/1000;
		poblacion[posicionCromosoma+i] = r;
	}
	for(int i = 0; i< cantidadPoblacionesCPU * cantCromosomasPoblacion; i++){
		fitnessActual[posicionFitness] = calcularFitnessRealCPU(poblacion, posicionCromosoma);
		fitnessOrdenadoHostCPU[posicionFitness] = fitnessActual[posicionFitness];
		posicionFitness++;
		posicionCromosoma = posicionCromosoma + cantGenesEnCromosoma;
	}
}
 void mainKernelRealCPU(float* poblacionActual, float* nuevaPoblacion, float* fitnessActual, float* nuevoFitness, int * poblacionActualAcambiar, int *  nuevaPoblacionAcambiar, float* individuosAMigrar, MersenneTwister *mt, int generacionActual, int nroPoblacion, int posActual, float *individuoAMigrarCPUaGPUhost, float *fitnessAMigrarCPUaGPUhost, float* fitnessOrdenado, int* vectorIndicesFitnessOrdenado, int iteracion, float* probabilidadRuleta, float* fitnessTotalParaRuleta, float* mejorIndividuo, float* mejorFitnessIndividuoCPU){
	 if(tipoSeleccion == 2){
		asignarProbabilidadRuletaRealCPU(fitnessActual, probabilidadRuleta, fitnessTotalParaRuleta, mt, nroPoblacion, posActual);
	}

	int posicionCromosoma1 = seleccionRealCPU(fitnessActual, mt, tipoSeleccion, nroPoblacion, posActual, probabilidadRuleta, vectorIndicesFitnessOrdenado);
	int posicionCromosoma2 = seleccionRealCPU(fitnessActual, mt, tipoSeleccion, nroPoblacion, posActual, probabilidadRuleta, vectorIndicesFitnessOrdenado);
	cruzamientoRepresentacionRealCPU(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidadCruzamiento, mt, tipoCruzamiento, nroPoblacion, posActual);
	mutacionRealCPU(nuevaPoblacion, probabilidadMutacion, mt, tipoMutacion, generacionActual, nroPoblacion, posActual);

	asignarFitnessRealCPU(nuevaPoblacion, nuevoFitness, nroPoblacion, posActual,fitnessOrdenado);
	reemplazoRealCPU(poblacionActual, nuevaPoblacion, poblacionActualAcambiar, nuevaPoblacionAcambiar, fitnessActual, nuevoFitness, tipoReemplazo, nroPoblacion, posActual);
	int indices[2];
	if(posActual == cantCromosomasPoblacion/2 -1){
		if((generacionesMigrar > 0) && ((iteracion + 1) % generacionesMigrar == 0)){
			//si posActual(numero hilo) es el ultimo del bloque
			individuosAMigrarRepresentacionRealCPU(nuevoFitness, nuevaPoblacion, individuosAMigrar, nroPoblacion, posActual, individuoAMigrarCPUaGPUhost, fitnessAMigrarCPUaGPUhost);
		}
		if(imprimirPoblacionEntera == 0){
			//obtengo el mejor individuo
			obtenerMejorIndividuoReal(nroPoblacion, nuevoFitness, indices);
			int posMejor = indices[0];
			for(int i = 0; i < cantGenesEnCromosoma; i++){
				mejorIndividuo[i + nroPoblacion * cantGenesEnCromosoma] = nuevaPoblacion[posMejor+i];
			}
			//asignar mejor fitness
			mejorFitnessIndividuoCPU[nroPoblacion] = nuevoFitness[posMejor/cantGenesEnCromosoma];
		}
	}
	//se pasa el individuo a migrar si hay al menos una poblacion en la gpu y soy la ultima poblacion de la cpu
}

 void obtenerMejoresIndividuosRealCPU(float* poblacion, float* fitness, float* mejorIndividuo, float* mejorFitnessIndividuoCPU){
 	//obtengo el mejor individuo
	 int indices[2];
	 for(int nroPoblacion = 0; nroPoblacion < cantidadPoblacionesCPU; nroPoblacion++){
		obtenerMejorIndividuoReal(nroPoblacion, fitness, indices);
		int posMejor = indices[0];
		for(int i = 0; i < cantGenesEnCromosoma; i++){
			mejorIndividuo[nroPoblacion * cantGenesEnCromosoma + i] = poblacion[posMejor+i];
		}
		//asignar mejor fitness
		mejorFitnessIndividuoCPU[nroPoblacion] = fitness[posMejor/cantGenesEnCromosoma];
	}
 }

/******************* Implementacion de Funciones de Migracion *****************/

//Obtiene el mejor individuo de una poblacion (1 bloque por poblacion)
//selecciona el mejor elemento
void obtenerMejorIndividuoReal(int nroPoblacion, float* vectorFitness, int indices[2]){
	float mejor = INT_MIN;
 	int indiceMejor;
 	float valorFitness;
 	int indiceMemoria = nroPoblacion * cantCromosomasPoblacion;
 	for(int i = 0; i< cantCromosomasPoblacion; i++){
 		valorFitness = vectorFitness[indiceMemoria+i];
 		if(valorFitness > mejor){
 			mejor = valorFitness;
 			indiceMejor = i;
 		}
 	}
 	int posicionCromosomaMejor = nroPoblacion * cantCromosomasPoblacion* cantGenesEnCromosoma+ indiceMejor * cantGenesEnCromosoma;
 	indices[0] = posicionCromosomaMejor;
 	indices[1] = indiceMejor;
}

 //Obtiene el indice del peor individuo y del fitness del peor individuo de una poblacion (1 bloque por poblacion) y retorna por referencia en el arreglo indices
 void obtenerPeorIndividuoReal(int nroPoblacion,float* vectorFitness, int indices[2]){
	 float peor = INT_MAX;
 	int indicePeor;
 	float valorFitness;
 	int posicionCromosomaPeor;
 	int indiceMemoria = nroPoblacion * cantCromosomasPoblacion;
 	for(int i = 0; i< cantCromosomasPoblacion; i++){
 		valorFitness = vectorFitness[indiceMemoria+i];
 		if(valorFitness < peor){
 			peor = valorFitness;
 			indicePeor = i;
 		}
 	}
 	posicionCromosomaPeor = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + indicePeor * cantGenesEnCromosoma;
 	indices[0] = posicionCromosomaPeor;
 	indices[1] = indicePeor;
 }

 void migracionRepresentacionRealCPU(float* poblacionActual, float* fitnessActual, float* individuosAMigrar, MersenneTwister *mt, float* individuoAMigrarGPUaCPUhost){
	unsigned int r = mt->genrand_int32() % cantCromosomasPoblacion;
	int indices[2];
	int posicionCromosomaEmigrante;
	int posicionCromosomaInmigrante;
	int posicionFitness;
	int aux;
	for(int bloq = 0; bloq < cantidadPoblacionesCPU; bloq++){
		if(bloq == 0){
			aux = cantidadPoblacionesCPU - 1;
		}else{
			aux = (bloq - 1) % cantidadPoblacionesCPU;
		}
		posicionCromosomaInmigrante = aux * cantGenesEnCromosoma;
		obtenerPeorIndividuoReal(bloq, fitnessActual, indices);

		posicionCromosomaEmigrante = indices[0];
		if(bloq == 0 && cantidadPoblacionesGPU > 0){
			for(int i = 0; i<cantGenesEnCromosoma; i++){
				poblacionActual[posicionCromosomaEmigrante+i] = individuoAMigrarGPUaCPUhost[i];
			}
		}else{
			for(int i = 0; i<cantGenesEnCromosoma; i++){
				poblacionActual[posicionCromosomaEmigrante+i] = individuosAMigrar[posicionCromosomaInmigrante+i];
			}
		}
		posicionFitness = bloq * cantCromosomasPoblacion + indices[1];
		fitnessActual[posicionFitness] = calcularFitnessRealCPU(poblacionActual, posicionCromosomaEmigrante);
	}
}

void individuosAMigrarRepresentacionRealCPU(float* nuevoFitness, float* nuevaPoblacion, float* individuosAMigrar, int nroPoblacion, int posActual, float *individuoAMigrarCPUaGPUhost, float *fitnessAMigrarCPUaGPUhost){
	int indices[2];
	obtenerMejorIndividuoReal(nroPoblacion, nuevoFitness, indices);
	int posicionMejorIndividuo = indices[0];
	int posicionMejorFitness = indices[1];
	if(cantidadPoblacionesGPU > 0 && nroPoblacion == cantidadPoblacionesCPU-1){
		for(int i = 0; i<cantGenesEnCromosoma; i++){
			individuoAMigrarCPUaGPUhost[i] = nuevaPoblacion[posicionMejorIndividuo+i];
		}
		fitnessAMigrarCPUaGPUhost[0] = nuevoFitness[nroPoblacion * cantCromosomasPoblacion + posicionMejorFitness];
	}else{
		for(int i = 0; i<cantGenesEnCromosoma; i++){
			individuosAMigrar[nroPoblacion*cantGenesEnCromosoma + i] = nuevaPoblacion[posicionMejorIndividuo+i];
		}
	}
}


/******************* Implementacion de Funciones de Selecccion *****************/

void asignarProbabilidadRuletaRealCPU(float* fitnessActual, float* probabilidadRuletaReal, float* fitnessTotalParaRuleta,  MersenneTwister *mt, int nroPoblacion, int posActual){
	if(posActual == 0){
		fitnessTotalParaRuleta[nroPoblacion] = 0;
		for(int i = nroPoblacion*cantCromosomasPoblacion; i < nroPoblacion*cantCromosomasPoblacion + cantCromosomasPoblacion; i++){
			fitnessTotalParaRuleta[nroPoblacion] += fitnessActual[i];
		}
		for(int i = nroPoblacion*cantCromosomasPoblacion; i < nroPoblacion*cantCromosomasPoblacion + cantCromosomasPoblacion; i++){
			probabilidadRuletaReal[i] = fitnessActual[i]/fitnessTotalParaRuleta[nroPoblacion] * 100;
		}
	}
}

int seleccionRealCPU(float* vectorFitness, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual, float* probabilidadRuleta, int* vectorIndicesFitnessOrdenado){
	int resultado = -1;
	if(ejecutarFuncion == 0){
		resultado = seleccionPorRangoRealCPU(vectorIndicesFitnessOrdenado, mt, nroPoblacion, posActual);
	}else{
		if(ejecutarFuncion == 1){
			resultado = seleccionPorTorneoRealCPU(vectorFitness, mt, nroPoblacion, posActual);
		}else{
			if(ejecutarFuncion == 2){
				resultado = seleccionRuedaRuletaRealCPU(probabilidadRuleta, mt, nroPoblacion, posActual);
			}
		}
	}
	return resultado;
}

//Seleccion por torneo
//selecciona 2 individuos al azar y devuelve la posicion del mejor
 int seleccionPorTorneoRealCPU(float* vectorFitness, MersenneTwister *mt, int nroPoblacion, int posActual){
	//printf("*** Seleccion por torneo real ***\n");
	unsigned int r = (mt->genrand_int32()) % cantCromosomasPoblacion;
	int posicionFitnessAleatoria1 = nroPoblacion * cantCromosomasPoblacion + r;
	int posicionCromosomaAleatoria1 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + r * cantGenesEnCromosoma;
	r = (mt->genrand_int32() + 1)% cantCromosomasPoblacion;
	int posicionFitnessAleatoria2 = nroPoblacion * cantCromosomasPoblacion + r;
	int posicionCromosomaAleatoria2 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + r * cantGenesEnCromosoma;
	if(vectorFitness[posicionFitnessAleatoria1] > vectorFitness[posicionFitnessAleatoria2])
		return posicionCromosomaAleatoria1;
	return posicionCromosomaAleatoria2;
}


 //Seleccion por rango
  int seleccionPorRangoRealCPU(int* vectorIndicesFitnessOrdenado, MersenneTwister *mt, int nroPoblacion, int posActual){
 	unsigned int indiceMejor =  mt->genrand_int32()% cantidadIndividuosSeleccionPorRango;
 	int posicionCromosoma = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + vectorIndicesFitnessOrdenado[nroPoblacion * cantCromosomasPoblacion + indiceMejor] * cantGenesEnCromosoma;
 	return posicionCromosoma;
 }

 //Seleccion por rueda de ruleta
int seleccionRuedaRuletaRealCPU(float* probabilidadRuleta, MersenneTwister *mt, int nroPoblacion, int posActual){
	float aux =  mt->genrand_int32();
 	float r = fmod(aux, 100);
 	float suma = probabilidadRuleta[nroPoblacion*cantCromosomasPoblacion];
 	int i = 0;
 	while((r > suma) && (i < cantCromosomasPoblacion - 1)){
 		i++;
 		suma = suma + probabilidadRuleta[nroPoblacion * cantCromosomasPoblacion + i];
 	}
	int posicionCromosoma = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + i * cantGenesEnCromosoma;
	return posicionCromosoma;
}

/******************* Implementacion de Funciones de Cruzamiento *****************/

 void cruzamientoRepresentacionRealCPU(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual){
	if(ejecutarFuncion == 0){
		cruzamientoAritmeticoIndividual(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual);
	}else{
		if(ejecutarFuncion == 1){
			cruzamientoAritmeticoSimple(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual);
		}else{
			if(ejecutarFuncion == 2){
				cruzamientoAritmeticoCompleto(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual);
			}
		}
	}
}

 void cruzamientoAritmeticoIndividual(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	//printf("*** Cruzamiento Aritmetico Individual ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;

	unsigned int prob;
	int genAcruzar = ((mt->genrand_int32()) % cantGenesEnCromosoma);
	prob = ((mt->genrand_int32()) % 101);
	for(int i=0; i<cantGenesEnCromosoma; i++){
		nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
		nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		if((i == genAcruzar) && (prob < probabilidad)){
      float aux = (mt->genrand_int32());
			float alfa = fmod(aux, 1);
			//printf("alfa = %f", alfa);
			nuevaPoblacion[posicionNuevoCromosoma1+i] = alfa * poblacionActual[posicionCromosoma2+i] + (1-alfa) * poblacionActual[posicionCromosoma2+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = alfa * poblacionActual[posicionCromosoma1+i] + (1-alfa) * poblacionActual[posicionCromosoma1+i];
		}
	}
}

 void cruzamientoAritmeticoSimple(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	unsigned int prob;
	unsigned int k = ((mt->genrand_int32()) % cantGenesEnCromosoma);
    float aux = (mt->genrand_int32());
	float alfa = fmod(aux, 1);
	for(int i=0; i<k; i++){
		nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
		nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
	}
	prob = ((mt->genrand_int32()) % 101);
	if(prob < probabilidad ){
		for(int i=k; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = alfa * poblacionActual[posicionCromosoma2+i] + (1-alfa) * poblacionActual[posicionCromosoma1+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = alfa * poblacionActual[posicionCromosoma1+i] + (1-alfa) * poblacionActual[posicionCromosoma2+i];
		}
	}else{
		for(int i=k; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		}
	}
}

 void cruzamientoAritmeticoCompleto(float* poblacionActual, float* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	unsigned int prob = ((mt->genrand_int32()) % 101);
    float aux = (mt->genrand_int32());
	float alfa = fmod(aux, 1);
	if(prob < probabilidad ){
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = alfa * poblacionActual[posicionCromosoma1+i] + (1-alfa) * poblacionActual[posicionCromosoma2+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = alfa * poblacionActual[posicionCromosoma2+i] + (1-alfa) * poblacionActual[posicionCromosoma1+i];
		}
	}else{
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		}
	}
}


/******************* Implementacion de Funciones de Mutacion *****************/


 void mutacionRealCPU(float* poblacion, float probabilidad, MersenneTwister *mt, int ejecutarFuncion, int generacionActual, int nroPoblacion, int posActual){
	if(ejecutarFuncion == 0){
		mutacionUniforme(poblacion, probabilidad, mt, nroPoblacion, posActual);
	}else{
		if(ejecutarFuncion == 1){
			mutacionNoUniforme(poblacion, probabilidad, mt, generacionActual, nroPoblacion, posActual);
		}
	}
}


 void mutacionUniforme(float* poblacion, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual){
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	unsigned int k;
	float left_k, right_k, aux1;
	float aux;
	unsigned int prob = ((mt->genrand_int32()) % 101);
	if(prob < probabilidad ){
		k = (mt->genrand_int32() + 1) % cantGenesEnCromosoma;
		left_k = poblacion[posicionNuevoCromosoma1 + (k - 1) % cantGenesEnCromosoma];
		right_k = poblacion[posicionNuevoCromosoma1 + (k + 1) % cantGenesEnCromosoma];
		aux = mt->genrand_real1();
		if(left_k > right_k){
			aux1 = right_k;
			right_k = left_k;
			left_k = aux1;
		}
		poblacion[posicionNuevoCromosoma1 + k] = left_k + aux * (right_k - left_k);
	}
	prob = ((mt->genrand_int32()) % 101);
	if(prob < probabilidad ){
		k = (mt->genrand_int32() + 1) % cantGenesEnCromosoma;
		left_k = poblacion[posicionNuevoCromosoma2 + (k - 1) % cantGenesEnCromosoma];
		right_k = poblacion[posicionNuevoCromosoma2 + (k + 1) % cantGenesEnCromosoma];
		aux = mt->genrand_real1();
		if(left_k > right_k){
			aux1 = right_k;
			right_k = left_k;
			left_k = aux1;
		}
		poblacion[posicionNuevoCromosoma2 + k] = left_k + aux * (right_k - left_k);
	}
}

 void mutacionNoUniforme(float* poblacion, float probabilidad, MersenneTwister *mt, int generacionActual, int nroPoblacion, int posActual){
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	unsigned int k;
	float left_k, right_k, resultado, r;
	int aux;
    float aux1 = (1 - (generacionActual/numeroGeneraciones));
	unsigned int prob = ((mt->genrand_int32()) % 101);
	if(prob < probabilidad ){
		k = (mt->genrand_int32() + 1) % cantGenesEnCromosoma;
		left_k = poblacion[posicionNuevoCromosoma1 + ((k - 1) % cantGenesEnCromosoma)];
		right_k = poblacion[posicionNuevoCromosoma1 + ((k + 1) % cantGenesEnCromosoma)];
		aux = (mt->genrand_int32()) % 1;
		r = (mt->genrand_int32());
		if(aux == 0){
			resultado = poblacion[posicionNuevoCromosoma1 + k] + ((right_k - poblacion[posicionNuevoCromosoma1 + k]) * r * (pow(aux1, gradoNoUniformidad)));
		}else{
			resultado = poblacion[posicionNuevoCromosoma1 + k] - ((poblacion[posicionNuevoCromosoma1 + k] - left_k) * r * (pow(aux1, gradoNoUniformidad)));
		}
		poblacion[posicionNuevoCromosoma1 + k] = resultado;
	}
	prob = ((mt->genrand_int32()) % 101);
	if(prob < probabilidad ){
		k = (mt->genrand_int32() + 1) % cantGenesEnCromosoma;
		left_k = poblacion[posicionNuevoCromosoma2 + ((k - 1) % cantGenesEnCromosoma)];
		right_k = poblacion[posicionNuevoCromosoma2 + ((k + 1) % cantGenesEnCromosoma)];
		aux = (mt->genrand_int32()) % 1;
		r = (mt->genrand_int32());
		if(aux == 0){
			resultado = poblacion[posicionNuevoCromosoma2 + k] + ((right_k - poblacion[posicionNuevoCromosoma2 + k]) * r * (pow(aux1, gradoNoUniformidad)));
		}else{
			resultado = poblacion[posicionNuevoCromosoma2 + k] - ((poblacion[posicionNuevoCromosoma2 + k] - left_k) * r * (pow(aux1, gradoNoUniformidad)));
		}
		poblacion[posicionNuevoCromosoma2 + k] = resultado;
	}
}

/******************* Implementacion de Funciones de fitness *****************/

 void asignarFitnessRealCPU(float* nuevaPoblacion, float* nuevoVectorFitness, int nroPoblacion, int posActual, float* fitnessOrdenado){
	//Obtengo posicion del primer cromosoma.
	int posicionCromosoma = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionFitness = posActual * 2 + nroPoblacion * cantCromosomasPoblacion;
	nuevoVectorFitness[posicionFitness] = calcularFitnessRealCPU(nuevaPoblacion, posicionCromosoma);
	nuevoVectorFitness[posicionFitness + 1] = calcularFitnessRealCPU(nuevaPoblacion, posicionCromosoma + cantGenesEnCromosoma);
	fitnessOrdenado[posicionFitness] = nuevoVectorFitness[posicionFitness];
	fitnessOrdenado[posicionFitness + 1] = nuevoVectorFitness[posicionFitness + 1];
}

 /******************** Implementacion de Funciones de reemplazo **************/

void reemplazoRealCPU(float * poblacionActual, float * nuevaPoblacion, int * poblacionActualAcambiar, int * nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int ejecutarFuncion, int nroPoblacion, int posActual){
 	if(ejecutarFuncion == 1){
 		reemplazoElitistaRealCPU(poblacionActual, nuevaPoblacion, poblacionActualAcambiar, nuevaPoblacionAcambiar, fitnessActual, nuevoFitness, nroPoblacion, posActual);
 	}
 }

void reemplazoElitistaRealCPU(float* poblacionActual, float* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int nroPoblacion, int posActual){
 	if(posActual == cantCromosomasPoblacion/2 - 1){
 		int cantAremplazar = (int) (porcentajeElitismo * cantCromosomasPoblacion / 100);
 		float peor = INT_MAX;
 		float mejor = INT_MIN;
 		int posPeor = -1;
 		int posMejor = -1;
 		int posFitness = nroPoblacion * cantCromosomasPoblacion;
 		for(int i = 0; i < cantAremplazar; i++){
 			if(fitnessActual[posFitness+i] < peor){
 				peor = fitnessActual[posFitness+i];
 				posPeor = i;
 			}
 			if(nuevoFitness[posFitness+i] > mejor){
 				mejor = nuevoFitness[posFitness+i];
 				posMejor = i;
 			}
 			poblacionActualAcambiar[posFitness+i] = 1;
 			nuevaPoblacionAcambiar[posFitness+i] = 1;
 		}
 		for(int i = cantAremplazar; i < cantCromosomasPoblacion; i++){
 			if(fitnessActual[posFitness+i] > peor){
 				poblacionActualAcambiar[posFitness+i] = 1;
 				poblacionActualAcambiar[posFitness+posPeor] = 0;
 				peor = INT_MAX;
 				posPeor = -1;
 				for(int j = 0; j <= i; j++){
 					if(poblacionActualAcambiar[posFitness+j] == 1){
 						if(fitnessActual[posFitness+j] < peor){
 							peor = fitnessActual[posFitness+j];
 							posPeor = j;
 						}
 					}
 				}
 			}else{
 				poblacionActualAcambiar[posFitness+i] = 0;
 			}

 			if(nuevoFitness[posFitness+i] < mejor){
 				nuevaPoblacionAcambiar[posFitness+i] = 1;
 				nuevaPoblacionAcambiar[posFitness + posMejor] = 0;
 				mejor = INT_MIN;
 				posMejor = -1;
 				for(int j = 0; j <= i; j++){
 					if(nuevaPoblacionAcambiar[posFitness+j] == 1){
 						if(nuevoFitness[posFitness+j] > mejor){
 							mejor = nuevoFitness[posFitness+j];
 							posMejor = j;
 						}
 					}
 				}
 			}else{
 				nuevaPoblacionAcambiar[posFitness+i] = 0;
 			}
 		}
 		for(int i = 0; i < cantAremplazar; i++){
 			int j = 0;
 			while(poblacionActualAcambiar[posFitness+j] == 0){
 				j++;
 			}
 			int k = 0;
 			while(nuevaPoblacionAcambiar[posFitness+k] == 0){
 				k++;
 			}
 			nuevoFitness[posFitness+k] = fitnessActual[posFitness+j];
 			int posNuevoCromosoma = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + k * cantGenesEnCromosoma;
 			int posCromosomaActual = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + j * cantGenesEnCromosoma;
 			for(int h = 0; h < cantGenesEnCromosoma; h++){
 				nuevaPoblacion[posNuevoCromosoma+h] = poblacionActual[posCromosomaActual+h];
 			}
 			poblacionActualAcambiar[posFitness+j] = 0;
 			nuevaPoblacionAcambiar[posFitness+k] = 0;
 		}
 	}
 }

/******************* Implementacion de Funciones del host *****************/
 void imprimirRealCPU(float* fitnessHost, float tamVectorFitness, float* poblacionHost, int tamVectorPoblacion, int iteracion){
	printf("\nPOBLACION EN CPU (iteracion %d):\n",iteracion);
  	for(int i = 0; i<totalGenesCPU; i++){
  		if(i%cantGenesEnCromosoma == 0){
  			//cout << "\n";
			printf("\n");
  		}
  		printf("%f ", poblacionHost[i]);
  	}
	printf("\n\nFITNESS EN CPU:\n\n");
  	for(int i = 0; i<cantCromosomasPoblacion * cantidadPoblacionesCPU; i++){
  		printf("%f ", fitnessHost[i] * (-1));
  	}
	printf("\n\n");
 }

void imprimirMejorIndividuoRealCPU(float* mejorFitnessIndividuoCPU, int tamVectorFitnessMejoresIndividuosCPU, float* mejorIndividuoCPU, int tamVectorMejoresIndividuosCPU, int iteracion){
	printf("\nMEJOR INDIVIDUO POR POBLACION EN CPU (iteracion %d):\n",iteracion);
 	for(int i = 0; i < cantGenesEnCromosoma * cantidadPoblacionesCPU; i++){
 		if(i%cantGenesEnCromosoma == 0){
			printf("\n");
		}
 		printf("%f ", mejorIndividuoCPU[i]);
 	}
	printf("\n\nFITNESS MEJOR INDIVIDUO POR POBLACION EN CPU:\n\n");
 	for(int i = 0; i < cantidadPoblacionesCPU; i++){
		printf("%f ", mejorFitnessIndividuoCPU[i] * (-1));
	}
	printf("\n\n");
}

 void representacionRealCPU(float *poblacionActualHost, float *nuevaPoblacionHost, float *fitnessActualHost, float *nuevoFitnessHost,int * poblacionActualAcambiar, int *  nuevaPoblacionAcambiar, float * individuosAMigrarHostCPU, MersenneTwister* mt, int iteracion, int tamVectorPoblacion, int tamVectorFitness, float *individuoAMigrarCPUaGPUhost, float *fitnessAMigrarCPUaGPUhost, float* fitnessOrdenadoHostCPU, int* indicesFitnessOrdenadoHostCPU, float* probabilidadRuletaHostCPU, float* fitnessTotalParaRuletaHostCPU, float* mejorFitnessIndividuoCPU, int tamVectorFitnessMejoresIndividuosCPU, float* mejorIndividuoCPU, int tamVectorMejoresIndividuosCPU){
 	int nroPoblacion = 0;
 	for(int i = 0; i < cantidadPoblacionesCPU*cantCromosomasPoblacion/2; i++){
 		nroPoblacion = i/(cantCromosomasPoblacion/2);
 		if((iteracion % 2) == 0){
 			mainKernelRealCPU(poblacionActualHost, nuevaPoblacionHost, fitnessActualHost, nuevoFitnessHost, poblacionActualAcambiar, nuevaPoblacionAcambiar, individuosAMigrarHostCPU, mt, iteracion, nroPoblacion, i%(cantCromosomasPoblacion/2), individuoAMigrarCPUaGPUhost, fitnessAMigrarCPUaGPUhost, fitnessOrdenadoHostCPU, indicesFitnessOrdenadoHostCPU, iteracion, probabilidadRuletaHostCPU, fitnessTotalParaRuletaHostCPU, mejorIndividuoCPU, mejorFitnessIndividuoCPU);
 		}else{
 			mainKernelRealCPU(nuevaPoblacionHost, poblacionActualHost, nuevoFitnessHost, fitnessActualHost, poblacionActualAcambiar, nuevaPoblacionAcambiar, individuosAMigrarHostCPU, mt, iteracion, nroPoblacion,  i%(cantCromosomasPoblacion/2), individuoAMigrarCPUaGPUhost, fitnessAMigrarCPUaGPUhost, fitnessOrdenadoHostCPU, indicesFitnessOrdenadoHostCPU, iteracion, probabilidadRuletaHostCPU, fitnessTotalParaRuletaHostCPU, mejorIndividuoCPU, mejorFitnessIndividuoCPU);
 		}
 	}
 	//Imprimo solo en la ultima iteracion o si esta en modo debug imprimo siempre
 	if((iteracion == numeroGeneraciones - 1) || (modoDebug == 1)){
		if((iteracion % 2) == 0){
			if(imprimirPoblacionEntera == 1)
				imprimirRealCPU(nuevoFitnessHost, tamVectorFitness, nuevaPoblacionHost, tamVectorPoblacion, iteracion);
			else
				imprimirMejorIndividuoRealCPU(mejorFitnessIndividuoCPU, tamVectorFitnessMejoresIndividuosCPU, mejorIndividuoCPU, tamVectorMejoresIndividuosCPU, iteracion);
		}else{
			if(imprimirPoblacionEntera == 1)
				imprimirRealCPU(fitnessActualHost, tamVectorFitness, poblacionActualHost, tamVectorPoblacion, iteracion);
			else
				imprimirMejorIndividuoRealCPU(mejorFitnessIndividuoCPU, tamVectorFitnessMejoresIndividuosCPU, mejorIndividuoCPU, tamVectorMejoresIndividuosCPU, iteracion);
		}
 	}
 }

#endif
